/*
 * Parses the QueryParser.xml file and converts it into in memory objects
 * 
 */
package com.querie.parser;

import java.io.*;

import java.util.List;
import java.util.Collections;
import java.util.ArrayList;

import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;

import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.NamedNodeMap;
import org.w3c.dom.*;
import org.xml.sax.SAXException;

/**
 *
 * @author a-skoshy
 */
public class QueryParser {

    //private String xmlFileName;
    private String[] regKeywords = {"[sS][eE][lL][eE][cC][tT]", "[fF][rR][oO][mM]", "[Ww][Hh][Ee][Rr][Ee]", "[Oo][Rr][Dd][Ee][Rr] [Bb][Yy]",
        "[Gg][Rr][Oo][Uu][Pp] [Bb][Yy]", "[Hh][Aa][Vv][Ii][Nn][Gg]"};
    //private String[] keywords= {"SELECT", "FROM", "WHERE", "ORDER BY", "GROUP BY", "HAVING"};
    private List<Keyword> keywords;
    private List<Rule> rules;
    private List<ReplaceWord> replaceWords;
    


    public QueryParser() {
        //xmlFileName = xml;
        keywords = new ArrayList<Keyword>();
        rules = new ArrayList<Rule>();
        replaceWords = new ArrayList<ReplaceWord>();
        

    }

    public void parseXML() {
        //File docFile = new File(xmlFileName);
        Element rootElement = null;
        Element keywordElems;
        Element replaceElems;
        Element ruleElems;

        String filePath = "QueryParser.xml";
        InputStream inputStream = QueryParser.class.getClassLoader().getResourceAsStream(filePath);

        Document doc = null;
        try {
            DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
            DocumentBuilder db = dbf.newDocumentBuilder();
            doc = db.parse(inputStream);
            //doc = db.parse(docFile);
            //System.out.println("Root element: " + doc.getDocumentElement().getNodeName());

            rootElement = doc.getDocumentElement();
            keywordElems = getFirstChildOfType(rootElement, "keywords");
            extractKeywords(keywordElems);
            Collections.sort(keywords);

            replaceElems = getFirstChildOfType(rootElement, "replacewords");
            extractReplacement(replaceElems);

            ruleElems = getFirstChildOfType(rootElement, "rules");
            extractRules(ruleElems);


        } catch (Exception e) {
            e.printStackTrace();
        }


    }

    public List<Keyword> getKeywords() {
        return keywords;
    }

    public List<Rule> getRules() {
        return rules;
    }

    public List<ReplaceWord> getReplaceWords() {
        return replaceWords;
    }

    private void extractKeywords(Element elem) throws Exception {
        for (Element childElement = getFirstChildOfType(elem, "keyword");
                childElement != null;
                childElement = getNextSiblingElement(childElement)) {
            keywords.add(createKeyword(childElement));
        }

    }

        private void extractReplacement(Element elem) throws Exception {
        for (Element childElement = getFirstChildOfType(elem, "replaceword");
                childElement != null;
                childElement = getNextSiblingElement(childElement)) {
            replaceWords.add(createReplaceword(childElement));
        }

    }

    
    private void extractRules(Element elem) throws Exception {
        for (Element childElement = getFirstChildOfType(elem, "rule");
                childElement != null;
                childElement = getNextSiblingElement(childElement)) {
            rules.add(createRule(childElement));
        }

    }

    private Keyword createKeyword(Element e) throws Exception {
        try {
            Keyword key = new Keyword();
            key.setKeyword(getElementText(e));
            key.setOrder(e.getAttribute("order"));
            key.setRegexp(e.getAttribute("regexp"));

            System.out.println(key);

            return key;
        } catch (NumberFormatException ex) {
            ex.printStackTrace();
            throw ex;
        }

    }

    private ReplaceWord createReplaceword(Element e) throws Exception {
        try {
            ReplaceWord key = new ReplaceWord(e.getAttribute("replace"),e.getAttribute("regexp"));
            
            System.out.println(key);

            return key;
        } catch (NumberFormatException ex) {
            ex.printStackTrace();
            throw ex;
        }

    }

    private Rule createRule(Element e) throws Exception {
        try {
            Rule rule = new Rule();
            List<String> startKeyList = new ArrayList<String>();
            List<String> endKeyList = new ArrayList<String>();

            rule.setName(e.getAttribute("name"));
            Element startKey = getFirstChildOfType(e, "startword");
            Element startExpr = getFirstChildOfType(startKey, "expression");
            String startType = startExpr.getAttribute("type");
            rule.setStartKeyExpression(startType);
            for (Element childElement = getFirstChildOfType(startExpr, "key");
                    childElement != null;
                    childElement = getNextSiblingElement(childElement)) {
                startKeyList.add(childElement.getAttribute("name"));
            }
            rule.setStartKeyList(startKeyList);

            //key.setOrder(e.getAttribute("order"));
            //key.setRegexp(e.getAttribute("regexp"));
            Element stopKey = getFirstChildOfType(e, "stopword");
            Element stopExpr = getFirstChildOfType(stopKey, "expression");
            String stopType = stopExpr.getAttribute("type");
            rule.setStopKeyExpression(stopType);

            for (Element childElement = getFirstChildOfType(stopExpr, "key");
                    childElement != null;
                    childElement = getNextSiblingElement(childElement)) {
                endKeyList.add(childElement.getAttribute("name"));
            }
            rule.setEndKeyList(endKeyList);


            //System.out.println(rule);

            return rule;
        } catch (Exception ex) {
            ex.printStackTrace();
            throw ex;
        }

    }

    /**
     * Returns element's text content.
     */
    public static String getElementText(Element element) {
        StringBuffer text = new StringBuffer();
        for (Node child = element.getFirstChild();
                child != null;
                child = child.getNextSibling()) {
            if (!(child instanceof Text)) {
                continue;
            }
            Text tn = (Text) child;
            text.append(tn.getData());
        }
        return text.toString();
    }

    /**
     * Returns first child element of a given type.
     */
    public static Element getFirstChildOfType(Element element, String tag) {
        Node child = null;

        for (child = element.getFirstChild();
                child != null;
                child = child.getNextSibling()) {
            if (child.getNodeType() != Node.ELEMENT_NODE) {
                continue;
            }
            if (tag.equals(((Element) child).getTagName())) {
                return (Element) child;
            }
        }
        return null;
    }

    /**
     * Returns next sibling element.
     */
    public static Element getNextSiblingElement(Node element) {
        Node sibling = element.getNextSibling();
        while ((sibling != null) && sibling.getNodeType() != Node.ELEMENT_NODE) {
            sibling = sibling.getNextSibling();
        }
        return (Element) sibling;
    }

    public static void main(String[] args) throws Exception {

        String text = "QueryParser.xml";
        QueryParser qp = new QueryParser();
        qp.parseXML();


    }
}
